#ifndef DockContainerWidgetH
#define DockContainerWidgetH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   DockContainerWidget.h
/// \author Uwe Kindler
/// \date   24.02.2017
/// \brief  Declaration of CDockContainerWidget class
//============================================================================


//============================================================================
//                                   INCLUDES
//============================================================================
#include <QFrame>

#include "ads_globals.h"
#include "AutoHideTab.h"
#include "DockWidget.h"

QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter)


namespace ads
{
class DockContainerWidgetPrivate;
class CDockAreaWidget;
class CDockWidget;
class CDockManager;
struct DockManagerPrivate;
class CFloatingDockContainer;
struct FloatingDockContainerPrivate;
class CFloatingDragPreview;
struct FloatingDragPreviewPrivate;
class CDockingStateReader;
class CAutoHideSideBar;
class CAutoHideTab;
struct AutoHideTabPrivate;
struct AutoHideDockContainerPrivate;


/**
 * 管理多个带有单个停靠小部件或选项卡停靠小部件的停靠区域的容器。
 * 每个支持停靠的窗口都包含一个 DockContainerWidget 实例，包括主应用程序窗口和所有浮动窗口。
 */
class ADS_EXPORT CDockContainerWidget : public QFrame
{
    Q_OBJECT
private:
    DockContainerWidgetPrivate* d; ///< 私有数据 (pimpl)
    friend class DockContainerWidgetPrivate;
    friend class CDockManager;
    friend struct DockManagerPrivate;
    friend class CDockAreaWidget;
    friend struct DockAreaWidgetPrivate;
    friend class CFloatingDockContainer;
    friend struct FloatingDockContainerPrivate;
    friend class CDockWidget;
    friend class CFloatingDragPreview;
    friend struct FloatingDragPreviewPrivate;
    friend CAutoHideDockContainer;
    friend CAutoHideTab;
    friend AutoHideTabPrivate;
    friend AutoHideDockContainerPrivate;
    friend CAutoHideSideBar;
protected:
    /**
     * 处理激活事件以更新 zOrderIndex
     */
    virtual bool event(QEvent *e) override;
    /**
     * 访问内部根分割器的函数
     */
    QSplitter* rootSplitter() const;
    /**
     * 创建并初始化停靠小部件自动隐藏容器到给定的区域。
     * 初始化将选项卡插入侧边选项卡小部件并隐藏它
     * 如果尝试插入到未启用配置的区域，则返回 nullptr
     */
    CAutoHideDockContainer* createAndSetupAutoHideContainer(SideBarLocation area, CDockWidget* DockWidget, int TabIndex = -1);
    /**
     * 创建根分割器的辅助函数
     */
    void createRootSplitter();
    /**
     * 创建侧边选项卡小部件的辅助函数
     */
    void createSideTabBarWidgets();
    /**
     * 将浮动小部件放入容器中
     */
    void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
    /**
     * 将停靠区域或停靠小部件放入容器中
     * 如果 TargetAreaWidget 为 nullptr，则 DropArea 表示容器的停靠区域。
     * 如果给定的 TargetAreaWidget 不为 nullptr，则 DropArea 表示给定的 TargetAreaWidget 中的停靠区域
     */
    void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget,
        int TabIndex = -1);

	/**
 * 将给定的Dock区域添加到此容器小部件中
 */
void addDockArea(CDockAreaWidget* dockAreaWidget, DockWidgetArea area = ads::CenterDockWidgetArea);

/**
 * 从此容器中移除给定的Dock区域
 */
void removeDockArea(CDockAreaWidget* area);

/**
 * 将状态保存到给定的流中
 */
void saveState(QXmlStreamWriter& stream) const;

/**
 * 从给定的流中恢复状态。
 * 如果Testing为true，则该函数仅从给定的流中解析数据，但不恢复任何内容。您可以在恢复状态之前使用此检查来检查错误的文件。
 */
bool restoreState(CDockingStateReader& stream, bool testing);

/**
 * 根据区域标识符返回最后添加的Dock区域小部件，如果未添加任何Dock区域，则返回0
 */
CDockAreaWidget* lastAddedDockAreaWidget(DockWidgetArea area) const;

/**
 * 如果hasSingleVisibleDockWidget()返回true，则返回唯一可见的Dock小部件。否则返回nullptr。
 */
CDockWidget* topLevelDockWidget() const;

/**
 * 如果容器只有一个单独可见的Dock区域，则返回该顶级Dock区域
 */
CDockAreaWidget* topLevelDockArea() const;

/**
 * 返回此浮动小部件中的所有Dock小部件的列表。
 * 根据实现的不同，可能存在Dock小部件对用户不可见且没有父小部件的情况。
 * 因此，简单调用findChildren()将无法正常工作。因此，此函数遍历所有Dock区域，并创建一个包含所有Dock小部件的列表。
 */
QList<CDockWidget*> dockWidgets() const;

/**
 * 强制Dock容器小部件根据容器中包含的Dock小部件的调整大小模式更新分割器的句柄。
 */
void updateSplitterHandles(QSplitter* splitter);

/**
 * 在内部的自动隐藏小部件列表中注册给定的浮动小部件
 */
void registerAutoHideWidget(CAutoHideDockContainer* autoHideWidget);

/**
 * 从注册的自动隐藏小部件列表中移除给定的自动隐藏小部件
 */
void removeAutoHideWidget(CAutoHideDockContainer* autoHideWidget);

/**
 * 处理自动隐藏小部件的小部件事件，以在自动隐藏标签上鼠标悬停时触发延迟显示或隐藏操作
 */
void handleAutoHideWidgetEvent(QEvent* e, QWidget* w);

public:
	/**
 * 默认构造函数
 */
CDockContainerWidget(CDockManager* DockManager, QWidget* parent = 0);

/**
 * 虚析构函数
 */
virtual ~CDockContainerWidget();

/**
 * 将 Dock 小部件添加到指定区域。
 * 如果 DockAreaWidget 不为空，则 area 参数表示 DockAreaWidget 中的区域。
 * 如果 DockAreaWidget 为空，则 Dockwidget 将被放置在容器中。
 * \return 返回包含新 Dock 小部件的 Dock 区域小部件
 */
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
    CDockAreaWidget* DockAreaWidget = nullptr, int Index = -1);

/**
 * 移除 Dock 小部件
 */
void removeDockWidget(CDockWidget* Dockwidget);

/**
 * 返回当前的 zOrderIndex
 */
virtual unsigned int zOrderIndex() const;

/**
 * 如果此容器小部件的 zOrderIndex 高于 Other 参数中容器小部件的索引，则返回 true
 */
bool isInFrontOf(CDockContainerWidget* Other) const;

/**
 * 返回给定全局位置处的 Dock 区域小部件，如果该位置没有 Dock 区域，则返回 nullptr
 */
CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const;

/**
 * 返回给定索引处的 Dock 区域小部件，如果索引超出范围，则返回 nullptr
 */
CDockAreaWidget* dockArea(int Index) const;

/**
 * 返回未关闭的 Dock 区域小部件列表
 * 如果 Dock 区域中的所有 Dock 小部件都已关闭，则该 Dock 区域将被关闭
 */
QList<CDockAreaWidget*> openedDockAreas() const;

/**
 * 返回所有打开的 Dock 区域中的所有打开的 Dock 小部件列表
 */
QList<CDockWidget*> openedDockWidgets() const;

/**
 * 如果容器中有打开的 Dock 区域，则返回 true。
 * 此函数比调用 openedDockAreas().isEmpty() 稍微快一些，因为它在找到打开的 Dock 区域后就返回。
 */
bool hasOpenDockAreas() const;

/**
 * 如果此 Dock 区域只有一个可见的 Dock 小部件，则返回 true。
 * 顶级小部件是真正的浮动小部件。只有顶级小部件的 isFloating() 函数可能返回 true。
 */
bool hasTopLevelDockWidget() const;

/**
 * 返回此容器中的 Dock 区域数
 */
int dockAreaCount() const;

/**
 * 返回可见的 Dock 区域数
 */
int visibleDockAreaCount() const;

/**
 * 如果此容器位于浮动小部件中，则返回 true
 */
bool isFloating() const;

/**
 * 用于调试目的，输出布局信息
 */
void dumpLayout();

/**
 * 返回此容器中所有 Dock 小部件的 Dock 小部件特性。
 * 通过对所有 Dock 小部件的标志进行按位与操作，将所有标志组合在一起。
 * 这意味着，如果只有一个 Dock 小部件不支持某个标志，则整个 Dock 区域都不支持该标志。
 */
CDockWidget::DockWidgetFeatures features() const;

	/**
 * 如果此dock容器在一个浮动窗口中，此函数返回浮动窗口。
 * 否则，返回nullptr。
 */
CFloatingDockContainer* floatingWidget() const;

/**
 * 调用此函数关闭除了KeepOpenArea之外的所有dock区域
 */
void closeOtherAreas(CDockAreaWidget* KeepOpenArea);

/**
 * 返回给定区域的侧边栏小部件
 */
CAutoHideSideBar* autoHideSideBar(SideBarLocation area) const;

/**
 * 访问函数用于自动隐藏小部件
 */
QList<CAutoHideDockContainer*> autoHideWidgets() const;

/**
 * 返回不包括自动隐藏侧边栏的内容矩形
 */
QRect contentRect() const;

/**
 * 返回映射到全局空间的内容矩形。
 * 内容矩形是dock管理器小部件的矩形减去自动隐藏侧边栏的几何形状。
 */
QRect contentRectGlobal() const;

/**
 * 返回拥有此容器的dock管理器
 */
CDockManager* dockManager() const;

Q_SIGNALS:

/**
 * 如果一个或多个dock区域已添加到内部dock区域列表中，则发出此信号。
 * 如果插入了多个dock区域，则只发出一次此信号。
 */
void dockAreasAdded();

/**
 * 如果创建了新的自动隐藏小部件，则发出此信号。
 */
void autoHideWidgetCreated(ads::CAutoHideDockContainer* AutoHideWidget);

/**
 * 如果一个或多个dock区域已被移除，则发出此信号。
 */
void dockAreasRemoved();

/**
 * 如果通过toggleView()函数打开或关闭了dock区域，则发出此信号。
 */
void dockAreaViewToggled(ads::CDockAreaWidget* DockArea, bool Open);
}; // class DockContainerWidget
} // namespace ads
//-----------------------------------------------------------------------------
#endif // DockContainerWidgetH
